﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using ServerLib;
using Timer = System.Threading.Timer;
using monitor_2_DBwork;

namespace monitor_server_2_WPF
{
    /// <summary>
    /// Логика взаимодействия для ObserveTabControl.xaml
    /// </summary>
    public partial class ObserveTabControl : Res.IControlForMainWindow
    {
        delegate void AddUserDelegate(UserData a);
        delegate void DelUserDelegate(int a);

        delegate void SendIntDelegate(int a);

        delegate void AddNewLogRecordDelegate(LogData a);

        private readonly MainWindow.LogEntriesChangedDelegate _changeNewLogs;
        private readonly MainWindow.UserEntriesChangedDelegate _changeUsersOnline;
        private int _newLogEntriesAmount;

        private const ListSortDirection DescSort = ListSortDirection.Descending;
        private string _prevRecordsNumber;
        //private int _logRecordsCount;
        private readonly Timer _logMaxChangeTimer;

        class UserData
        {
            public string Login { get; set; }
            public string Group { get; set; }
            public string Region { get; set; }
            public string LoginTime { get; set; }
            public string IpAddress { get; set; }
        }

        class LogData
        {
            public string Login { get; set; }
            public string Group { get; set; }
            public string Region { get; set; }
            public string Category { get; set; }
            public string EventName { get; set; }
            public DateTime EventTime { get; set; }
        }

        private readonly ObservableCollection<UserData> _userGridItems;
        private readonly UsersListChangedDelegate _usersListChanged;

        private readonly ObservableCollection<LogData> _logGridItems;
        private readonly NewLogRecordDelegate _newLogRecord;

        public ObserveTabControl(MainWindow.LogEntriesChangedDelegate logs, MainWindow.UserEntriesChangedDelegate users)
        {
            InitializeComponent();

            _changeNewLogs = logs;
            _changeUsersOnline = users;

            _logMaxChangeTimer = new Timer(MaxChangeTimerCallback);

            Item1.Header = Res.Rm.GetString("Observation");
            MainGrid.Background = new SolidColorBrush(Res.LighBlack);
            UserBox.Text = Res.Rm.GetString("Users") + ' ' + Res.Rm.GetString("Online").ToLower();
            LogBox.Text = Res.Rm.GetString("Events");
            //UserGrid
            var ugc1 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("UserName"),
                Width = 155,
                Binding = new Binding("Login")
            };
            var ugc2 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Access"),
                Width = 110,
                Binding = new Binding("Group")
            };
            var ugc3 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Region"),
                Width = 140,
                Binding = new Binding("Region")
            };
            var ugc4 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("LoginTime"),
                Width = 140,
                Binding = new Binding("LoginTime")
            };

            var ugc5 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("IPAddress"),
                Width = 120,
                Binding = new Binding("IpAddress")
            };

            UserGrid.Columns.Add(ugc1);
            UserGrid.Columns.Add(ugc2);
            UserGrid.Columns.Add(ugc3);
            UserGrid.Columns.Add(ugc4);
            UserGrid.Columns.Add(ugc5);
            UserGrid.AutoGenerateColumns = false;
            UserGrid.CanUserAddRows = false;
            UserGrid.CanUserDeleteRows = false;
            UserGrid.IsReadOnly = true;
            _userGridItems = new ObservableCollection<UserData>();
            UserGrid.ItemsSource = _userGridItems;


            //LogGrid
            var lgc1 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("UserName"),
                Width = 155,
                Binding = new Binding("Login")
            };
            var lgc2 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Access"),
                Width = 110,
                Binding = new Binding("Group")
            };
            var lgc3 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Region"),
                Width = 100,
                Binding = new Binding("Region")
            };
            var lgc4 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Category"),
                Width = 100,
                Binding = new Binding("Category")
            };
            var lgc5 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Event"),
                Width = 270,
                Binding = new Binding("EventName")
            };
            var lgc6 = new DataGridTextColumn
            {
                Header = Res.Rm.GetString("Date"),
                Width = 140,
                Binding = new Binding("EventTime") { StringFormat = "dd/MM/yyyy hh:mm" },
                
            };
            LogGrid.Columns.Add(lgc1);
            LogGrid.Columns.Add(lgc2);
            LogGrid.Columns.Add(lgc3);
            LogGrid.Columns.Add(lgc4);
            LogGrid.Columns.Add(lgc5);
            LogGrid.Columns.Add(lgc6);
            LogGrid.AutoGenerateColumns = false;
            LogGrid.CanUserAddRows = false;
            LogGrid.CanUserDeleteRows = false;
            LogGrid.IsReadOnly = true;
            _logGridItems = new ObservableCollection<LogData>();
            LogGrid.ItemsSource = _logGridItems;
            LogGrid.Items.SortDescriptions.Add(new SortDescription("EventTime", DescSort));

            _newLogRecord = NewLogRecordAppeared;
            Server.NewLogRecordEvent += _newLogRecord;
            
            _usersListChanged = OnUsersListChanged;
            Server.UsersListChangedEvent += _usersListChanged;

            //Numeric
            var upimage = new Image {Source = Res.GetBitMapFromPng("arrowup_16")};
            UpButton.Content = upimage;

            var downimage = new Image {Source = Res.GetBitMapFromPng("arrowdown_16")};
            DownButton.Content = downimage;

            _prevRecordsNumber = MaximumLogEntriesBox.Text = DBwork.GetOptionValue(Server.ServerLogLastRecordsCountOptionName);
            MaximumLogEntriesBox.TextChanged += MaximumLogEntriesBox_TextChanged;
            MaxEntriesLabel.Text = Res.Rm.GetString("MaxLogEntries");

            BeyondLogPanel.Orientation = Orientation.Horizontal;


            GridSplitter.Background = new SolidColorBrush(Res.LighBlack);
        }

        public bool IsTabVisible { get; set; }

        private void DeleteLogRecords(int delAmount)
        {
            for (int i = 0; i < delAmount; i++)
            {
                _logGridItems.RemoveAt(0);
            }
        }

        private void MaxChangeTimerCallback(object state)
        {
            //var tb = MaximumLogEntriesBox;
            _logMaxChangeTimer.Change(Timeout.Infinite, Timeout.Infinite);
            DBwork.AddOrSetOptionValue(Server.ServerLogLastRecordsCountOptionName, _prevRecordsNumber);
            int comp = _logGridItems.Count - int.Parse(_prevRecordsNumber);
            if (comp > 0)
            {
                SendIntDelegate id = DeleteLogRecords;
                Dispatcher.Invoke(id, new object[] {comp});
            }
                
        }


        //Maximum entries value changed
        void MaximumLogEntriesBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            var tb = sender as TextBox;
            int a;
            if (!int.TryParse(tb.Text, out a))
            {
                tb.Text = _prevRecordsNumber;
            }
            else
            {
                _prevRecordsNumber = tb.Text;
                _logMaxChangeTimer.Change(600, 1000);
                //DBwork.AddOrSetOptionValue(Server.ServerLogLastRecordsCountOptionName, _prevRecordsNumber);
                //int comp = _logGridItems.Count - int.Parse(_prevRecordsNumber);
                //if (comp > 0)
                //    for (int i = 0; i < comp; i++)
                //    {
                //        _logGridItems.RemoveAt(0);
                //    }
            }
        }

        private void AddUser(UserData u)
        {
            _userGridItems.Add(u);
            _changeUsersOnline(_userGridItems.Count.ToString(CultureInfo.InvariantCulture));
        }

        private void DelUser(int pos)
        {
            _userGridItems.RemoveAt(pos);
            _changeUsersOnline(_userGridItems.Count.ToString(CultureInfo.InvariantCulture));
        }

        private void OnUsersListChanged(string login, string access, string region, string loggedIn, string ip, bool added)
        {
            
            if (added)
            {
                var user = new UserData
                    {
                        Login = login,
                        Group = access,
                        Region = region,
                        LoginTime = loggedIn,
                        IpAddress = ip
                    };

                AddUserDelegate add = AddUser;
                Dispatcher.Invoke(add, new object[]{user});
            }
            else
            {
                int pos = _userGridItems.TakeWhile(user => user.Login != login).Count();
                //foreach (var user in _userGridItems)
                //{
                //    if (user.Login == login)
                //        break;
                //    pos++;
                //}
                if (pos < _userGridItems.Count)
                {
                    DelUserDelegate del = DelUser;
                    Dispatcher.Invoke(del, new object[] { pos });
                }
                    //_userGridItems.RemoveAt(pos);
            }
            //UserGrid.Items.Refresh();
        }

        private void AddLogRecord(LogData ld)
        {
            if (_logGridItems.Count > int.Parse(MaximumLogEntriesBox.Text) - 1)
                _logGridItems.RemoveAt(0);
            var cat = ld.Category;
            ld.Category = Res.Rm.GetString(ld.Category) ?? "undefined";
            _logGridItems.Add(ld);
            if(!IsTabVisible)
                _changeNewLogs((++_newLogEntriesAmount).ToString(CultureInfo.InvariantCulture), cat);
        }

        private void NewLogRecordAppeared(string login, string access, string region, string category, string eventName,
                                          DateTime date)
        {
            var ld = new LogData
                {
                    Login = login,
                    Group = access,
                    Region = region,
                    Category = category,
                    EventName = eventName,
                    EventTime = date
                };
            //ld.Category = Res.Rm.GetString(category) ?? "undefined";
            AddNewLogRecordDelegate del = AddLogRecord;
            Dispatcher.Invoke(del, new object[] {ld});
        }

        public UIElement GetControl(out MainWindow.HidingDelegate del)
        {
            del = () =>
            {
                IsTabVisible = false;
            };

            Reset();
            IsTabVisible = true;
            return this;
        }

        public void Reset()
        {
            _newLogEntriesAmount = 0;
            _changeNewLogs("0", "reset");
        }

        private void UpButton_Click(object sender, RoutedEventArgs e)
        {
            MaximumLogEntriesBox.Text = (int.Parse(MaximumLogEntriesBox.Text) + 1).ToString(CultureInfo.InvariantCulture);
        }

        private void DownButton_Click(object sender, RoutedEventArgs e)
        {
            int a = int.Parse(MaximumLogEntriesBox.Text);
            if(a > 1)
                MaximumLogEntriesBox.Text = (a - 1).ToString(CultureInfo.InvariantCulture);
        }
    }
}
